﻿using System;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Sustainalytics.Entities;
using System.Collections.Generic;
using Sustainalytics.DynamicsCRMGateway.Entities;
using Microsoft.Xrm.Sdk;

namespace Sustainalytics.DynamicsCRMGateway.Tests
{
    [TestClass]
    public class CrmClaimsTests
    {
        private const string _connectionString = "Url=https://sustainalytics0.crm4.dynamics.com;Username=client.platform@sustainalytics.com;Password=M46iaHerm3s21!";
        private const string _claimValue = "Allow.Read";
        private List<Guid> _featureIds = new List<Guid>();
        private List<Guid> _claimIds = new List<Guid>();
        private List<Guid> _accountIds = new List<Guid>();
        private List<Guid> _accountFeatureIds = new List<Guid>();
        private CrmServiceContext _crmServiceContext;
        private const string _prefix = "Unit_Test_";

        private static List<Claim> _claims = new List<Claim>() { 
                new Claim() { Name = _prefix + "Home/dashboard", Value = _claimValue, ClaimId = Guid.NewGuid() }, 
                new Claim() { Name = _prefix + "Company/Overview", Value = _claimValue, ClaimId = Guid.NewGuid() }, 
                new Claim() { Name = _prefix + "Tools/screening", Value = _claimValue, ClaimId = Guid.NewGuid() }
             };

        private static List<string> _featureNames = new List<string>(){
            _prefix + "Dashboard", 
            _prefix + "News section",
            _prefix + "Calendar section",
            _prefix + "Overview tab on company pages",
            _prefix + "Screening tool full access",
        };


        private static List<Feature> _features = new List<Feature>() { 
                new Feature() { Name = _featureNames[0], FeatureId = Guid.NewGuid(), ParentFeature=_packageFeature}, 
                new Feature() { Name = _featureNames[1], FeatureId = Guid.NewGuid(), ParentFeature=_packageFeature},
                new Feature() { Name = _featureNames[2], FeatureId = Guid.NewGuid(), ParentFeature=_packageFeature},
                new Feature() { Name = _featureNames[3], FeatureId = Guid.NewGuid(), ParentFeature=_packageFeature}, 
                new Feature() { Name = _featureNames[4], FeatureId = Guid.NewGuid(), ParentFeature=_packageFeature},
            };

        private static Feature _packageFeature = new Feature() { Name = _prefix + "package", FeatureId = Guid.NewGuid(), IsPackage = true};

        private static List<string> _accountNames = new List<string>(){
            _prefix + "AMD", 
            _prefix + "ACM Advisors",
            _prefix + "ABN AMRO NV",
            _prefix + "Sustainalitycs",
        };

        private static List<Sustainalytics.DynamicsCRMGateway.Entities.Account> _accounts = new List<Sustainalytics.DynamicsCRMGateway.Entities.Account>() { 
                new Sustainalytics.DynamicsCRMGateway.Entities.Account() { Name = _accountNames[0], AccountId = Guid.NewGuid() }, 
                new Sustainalytics.DynamicsCRMGateway.Entities.Account() { Name = _accountNames[1], AccountId = Guid.NewGuid() }, 
                new Sustainalytics.DynamicsCRMGateway.Entities.Account() { Name = _accountNames[2], AccountId = Guid.NewGuid() },
                new Sustainalytics.DynamicsCRMGateway.Entities.Account() { Name = _accountNames[3], AccountId = Guid.NewGuid() }
            };

        private static List<Tuple<AccountFeature, Sustainalytics.DynamicsCRMGateway.Entities.Account, Feature>> _accountFeatures = 
            new List<Tuple<AccountFeature, Sustainalytics.DynamicsCRMGateway.Entities.Account, Feature>>() { 
                new Tuple<AccountFeature, Sustainalytics.DynamicsCRMGateway.Entities.Account, Feature>(new AccountFeature() { Id = Guid.NewGuid()}, _accounts[0], _features[0]),

                new Tuple<AccountFeature, Sustainalytics.DynamicsCRMGateway.Entities.Account, Feature>(new AccountFeature() { Id = Guid.NewGuid()}, _accounts[1], _features[1]),
                new Tuple<AccountFeature, Sustainalytics.DynamicsCRMGateway.Entities.Account, Feature>(new AccountFeature() { Id = Guid.NewGuid()}, _accounts[1], _features[2]),
                new Tuple<AccountFeature, Sustainalytics.DynamicsCRMGateway.Entities.Account, Feature>(new AccountFeature() { Id = Guid.NewGuid()}, _accounts[1], _features[3]),

                new Tuple<AccountFeature, Sustainalytics.DynamicsCRMGateway.Entities.Account, Feature>(new AccountFeature() { Id = Guid.NewGuid()}, _accounts[2], _features[3]),

                new Tuple<AccountFeature, Sustainalytics.DynamicsCRMGateway.Entities.Account, Feature>(new AccountFeature() { Id = Guid.NewGuid()}, _accounts[3], _packageFeature)
            };

        [TestInitialize]
        public void Initialize()
        {
            var crmServiceContextFactory = new CrmServiceContextFactory();
            _crmServiceContext = crmServiceContextFactory.GetCrmServiceContext(_connectionString);

            CreateTestAccounts();
            CreateTestFeatures();

            CreateTestClaimFeatures();

            CreateTestClaims();

            CreateTestFeaturePackage();
            
            CreateTestAccountFeatures();
        }

        private void CreateTestFeaturePackage()
        {
            var list = new List<Feature>() { _packageFeature };
            AddEntities(list);

            _packageFeature.ChildFeatures = new List<Feature>(_features);
            
            UpdateEntities(list);
        }

        private void CreateTestAccountFeatures()
        {
            var accfeatures = _accountFeatures.Select(x => x.Item1).ToList();
            AddEntities(accfeatures);
            accfeatures.ForEach(af => _accountFeatureIds.Add(af.AccountFeatureId.Value));

            UpdateEntities(_accountFeatures.Select(x =>
            {
                x.Item1.Account = x.Item2;
                x.Item1.Feature = x.Item3;
                return x.Item1;
            }).ToList());
        }

        private void CreateTestClaimFeatures()
        {
            _claims[0].Features = new List<Feature>() { _features[0], _features[1], _features[2] };
            _claims[1].Features = new List<Feature>() { _features[3] };
            _claims[2].Features = new List<Feature>() { _features[4] };
        }

        private void CreateTestAccounts()
        {
            AddEntities(_accounts);
            _accounts.ForEach(a => _accountIds.Add(a.AccountId.Value));
        }

        private void CreateTestFeatures()
        {
            _features.ForEach(a => _featureIds.Add(a.FeatureId.Value));
        }

        private void CreateTestClaims()
        {
            AddEntities(_claims );
            _claims.ForEach(a => _claimIds.Add(a.ClaimId.Value));
        }

        private void AddEntities<T>(List<T> entities) where T: Entity
        {
            var claimRepo = new CrmRepository<T>(_crmServiceContext);
            claimRepo.Create(entities);
        }

        private void UpdateEntities<T>(List<T> entities) where T : Entity
        {
            var claimRepo = new CrmRepository<T>(_crmServiceContext);
            claimRepo.Update(entities);
        }

        [TestCleanup]
        public void Cleanup()
        {
            DeleteTestClaims();
            DeleteTestAccountFeature();
            DeleteTestAccounts();
            DeleteTestFeatures();
            DeleteTestAccountFeatures();
        }

        private void DeleteTestAccountFeatures()
        {
            _accountFeatures.ForEach(x => { x.Item1.Account = null; x.Item1.Feature = null; });
        }

        private void DeleteTestAccountFeature()
        {
            DeleteTestEntity<AccountFeature>(_accountFeatureIds);
        }

        private void DeleteTestFeatures()
        {
            DeleteTestEntity<Feature>(new List<Guid>() { _packageFeature.FeatureId.Value });
            DeleteTestEntity<Feature>(_featureIds);
            _packageFeature.ChildFeatures = null;
        }

        private void DeleteTestAccounts()
        {
            DeleteTestEntity<Sustainalytics.DynamicsCRMGateway.Entities.Account>(_accountIds);
        }

        private void DeleteTestClaims()
        {
            DeleteTestEntity<Claim>(_claimIds);
        }

        private void DeleteTestEntity<T>(List<Guid> ids) where T : Entity
        {
            var repo = new CrmRepository<T>(_crmServiceContext);

            repo.Delete(ids);
        }

        [TestMethod]
        public void TestReadClaimsFeatures()
        {
            var claimsFeatureRepository = new FeatureClaimsRepository(_connectionString);
            var claimsMap = new List<ClaimMap>(claimsFeatureRepository.ReadAll());
            var myClaimsMap = claimsMap.Where(x => x.Permission.StartsWith(_prefix)).ToList();

            Assert.IsTrue(myClaimsMap.Count == _featureNames.Count);

            for (int i = 0; i < myClaimsMap.Count; i++)
            {
                Assert.IsTrue(_featureNames.Contains(myClaimsMap[i].Permission));
                Assert.IsTrue(myClaimsMap[i].Claims.Count == 1);
            }
        }

        [TestMethod]
        public void TestReadClaimsAccounts()
        {
            var claimsAccountRepository = new AccountClaimsRepository(_connectionString);

            var claimUsersMap = new List<UserClaim>(claimsAccountRepository.ReadAll());
            var myClaimUsersMap = claimUsersMap.Where(x => x.Account.StartsWith(_prefix)).ToList();

            Assert.IsTrue(myClaimUsersMap.Count == _accounts.Count);

            for (int i = 0; i < myClaimUsersMap.Count; i++)
            {
                Assert.IsTrue(_accountNames.Contains(myClaimUsersMap[0].Account));

                if (myClaimUsersMap[i].Account == _accountNames[1])
                    Assert.IsTrue(myClaimUsersMap[i].Claims.Count == 2);
                else if (myClaimUsersMap[i].Account == _accountNames[3])
                    Assert.IsTrue(myClaimUsersMap[i].Claims.Count == 3);
                else
                    Assert.IsTrue(myClaimUsersMap[i].Claims.Count == 1);
            }
        }
    }
}
